/*
@Time : 2020/12/29 2:18 下午
@Author : chenle
@File : database
@Software: GoLand
*/
package lego

import (
	"fmt"
	"log"

	"time"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

var db *gorm.DB

func GetDB() *gorm.DB {
	return db
}

type Model struct {
	ID        uint    `gorm:"primary_key"json:"id"`
	CreatedAt string  `gorm:"type:varchar(30);default:null"json:"created_at"`
	UpdatedAt string  `gorm:"type:varchar(30);default:null"json:"updated_at"`
	DeletedAt *string `gorm:"type:varchar(30);default:null"json:"deleted_at"`
}

//// Logger :
//type Logger interface {
//	Infof(format string, a ...interface{})
//	Warnf(format string, a ...interface{})
//	Errorf(format string, a ...interface{})
//}

// MyLogger :
type MyLogger struct {
	logger *log.Logger
}

// 初始化数据库
func (l *Lego) initDataBase(values ...interface{}) {

	SysInfo(">>>>>>>> |db model is initing")
	dbConf := confValue.GetMysqlConf()
	//fmt.Println("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True&loc=Local",
	//	dbConf.Username,
	//	dbConf.Password,
	//	dbConf.Address,
	//	dbConf.DbName)

	var err error
	//fmt.Println(*dbConf)
	//mysql","root:root@tcp(localhost)/dbname?charset=utf8&parseTime=True&loc=Local")
	db, err = gorm.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		dbConf.Username,
		dbConf.Password,
		dbConf.Address,
		dbConf.DbName))

	if err != nil {
		log.Fatalf("models.Setup err: %v", err)
	}

	gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string {
		return "t_" + defaultTableName
	}
	db.SingularTable(true)

	//var i gorm.LogWriter = MyLogger{logger: logging.Logger}
	//log := gorm.Logger{LogWriter: i}
	//db.SetLogger(log)
	db.LogMode(true)

	db.SingularTable(true)

	// 注册钩子函数
	db.Callback().Create().Replace("gorm:update_time_stamp", updateTimeStampForCreateCallback)
	db.Callback().Update().Replace("gorm:update_time_stamp", updateTimeStampForUpdateCallback)
	db.Callback().Delete().Replace("gorm:delete", deleteCallback)
	db.DB().SetMaxIdleConns(dbConf.MaxIdleConns)
	db.DB().SetMaxOpenConns(dbConf.MaxOpenConns)
	db.DB().SetConnMaxLifetime(time.Duration(dbConf.ConnMaxLifetime * int64(time.Millisecond)))
	db.AutoMigrate(values...)
	l.Engine.DB = db

	SysInfo("<<<<<<<< |db model init success")
}

// // 注册新建钩子在持久化之前
func updateTimeStampForCreateCallback(scope *gorm.Scope) {

	if !scope.HasError() {
		nowTime := time.Now().Format("2006-01-02 15:04:05")
		if createTimeField, ok := scope.FieldByName("CreatedAt"); ok {
			if createTimeField.IsBlank {
				createTimeField.Set(nowTime)
			}
		}

		if modifyTimeField, ok := scope.FieldByName("UpdatedAt"); ok {
			if modifyTimeField.IsBlank {
				modifyTimeField.Set(nowTime)
			}
		}
	}
}

// 注册更新钩子在持久化之前
func updateTimeStampForUpdateCallback(scope *gorm.Scope) {
	if _, ok := scope.Get("gorm:update_column"); !ok {
		scope.SetColumn("UpdatedAt", time.Now().Format("2006-01-02 15:04:05"))
	}
}

// 注册删除钩子在删除之前
func deleteCallback(scope *gorm.Scope) {
	if !scope.HasError() {
		var extraOption string
		if str, ok := scope.Get("gorm:delete_option"); ok {
			extraOption = fmt.Sprint(str)
		}

		deletedOnField, hasDeletedOnField := scope.FieldByName("DeletedAt")

		if !scope.Search.Unscoped && hasDeletedOnField {
			scope.Raw(fmt.Sprintf(
				"UPDATE %v SET %v=%v %v %v",
				scope.QuotedTableName(),
				scope.Quote(deletedOnField.DBName),
				scope.AddToVars(time.Now().Format("2006-01-02 15:04:05")),
				addExtraSpaceIfExist(scope.CombinedConditionSql()),
				addExtraSpaceIfExist(extraOption),
			)).Exec()
		} else {
			scope.Raw(fmt.Sprintf(
				"DELETE FROM %v%v%v",
				scope.QuotedTableName(),
				addExtraSpaceIfExist(scope.CombinedConditionSql()),
				addExtraSpaceIfExist(extraOption),
			)).Exec()
		}
	}
}
func addExtraSpaceIfExist(str string) string {
	if str != "" {
		return " " + str
	}
	return ""
}
